﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ValiVIN
{
    /// <summary>
    /// Manufacturer and Country info pulled from
    /// http://en.wikibooks.org/wiki/Vehicle_Identification_Numbers_(VIN_codes)/World_Manufacturer_Identifier_(WMI)
    /// </summary>
    public static class VINCheck
    {
        #region constants
        private const int _CHECKDIGIT = 8;
        internal const int _REQUIRED_LENGTH = 17;
        private static readonly Regex _validCharacters = new Regex("[^a-hj-npr-zA-HJ-NPR-Z0-9]");
        private static readonly int[] _WEIGHTS = { 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 };

        #endregion

        /// <summary>
        /// Checks if a string is a valid VIN (Vehicle Identification Number).
        /// NOTE: VIN numbers were not standardized until 1981.
        /// Any VIN from a Vehicle prior to 1981 will likely return false.
        /// </summary>
        /// <param name="vin">VIN to check</param>
        /// <returns>true if validation passes</returns>
        public static bool IsValid(string vin)
        {
            //get the obvious cases out of the way
            if (String.IsNullOrEmpty(vin)) { return false; }
            if (vin.Length != _REQUIRED_LENGTH) { return false; }
            if (_validCharacters.IsMatch(vin)) { return false; }

            char checkSum = CheckSumValue(vin);
            return checkSum == vin.ToUpper()[_CHECKDIGIT];
        }

        /// <summary>
        /// Takes a 17 digit VIN string and calculates what the checksum value should be.
        /// The CheckSum value is the 9th digit in the VIN.
        /// </summary>
        /// <param name="vin">VIN to check</param>
        /// <returns>Correct CheckSum value.
        /// If VIN contains incorrect characters, or is the wrong length it returns ' '</returns>
        public static char GetCheckSumValue(string vin)
        {
            //get the obvious cases out of the way
            if (String.IsNullOrEmpty(vin)) { return ' '; }
            if (vin.Length != _REQUIRED_LENGTH) { return ' '; }
            if (_validCharacters.IsMatch(vin)) { return ' '; }

            return CheckSumValue(vin);
        }

        #region private methods

        #region Checksum

        private static int CharValue(char vChar)
        {
            int i = 0;

            switch (vChar)
            {
                case 'A':
                case 'J':
                    i = 1;
                    break;

                case 'B':
                case 'K':
                case 'S':
                    i = 2;
                    break;

                case 'C':
                case 'L':
                case 'T':
                    i = 3;
                    break;

                case 'D':
                case 'M':
                case 'U':
                    i = 4;
                    break;

                case 'E':
                case 'N':
                case 'V':
                    i = 5;
                    break;

                case 'F':
                case 'W':
                    i = 6;
                    break;

                case 'G':
                case 'P':
                case 'X':
                    i = 7;
                    break;

                case 'H':
                case 'Y':
                    i = 8;
                    break;

                case 'R':
                case 'Z':
                    i = 9;
                    break;

                default:
                    i = Int32.Parse(vChar.ToString());
                    break;

            }
            return i;
        }

        private static int CalculateSum(string vin)
        {
            int Sum = 0;
            for (int i = 0; i <= vin.Length - 1; i++)
            {
                Sum += CharValue(vin[i]) * _WEIGHTS[i]; ;
            }
            return Sum;
        }

        private static char CheckSumValue(string vin)
        {
            int mod = CalculateSum(vin.ToUpper()) % 11;
            return (mod == 10) ? 'X' : mod.ToString()[0];
        }

        #endregion

        #region Region

        /// <summary>
        /// Determines the Regioin for a given VIN
        /// </summary>
        /// <param name="vin"></param>
        /// <returns></returns>
        public static string Region(string vin)
        {
            if (string.IsNullOrEmpty(vin) || vin.Length != _REQUIRED_LENGTH)
            {
                return string.Empty;
            }

            string nvin = vin.ToUpper();
            string region = string.Empty;

            string s = nvin.Substring(0, 1).ToUpper();

            if (s.CompareTo("0") > 0 && s.CompareTo("6") < 0)
            {
                region = "North America";
            }
            else if (s == "6" || s == "7")
            {
                region = "Oceanic";
            }
            else if (s == "0" || s == "8" || s == "9")
            {
                region = "South America";
            }
            else if (s.CompareTo("A") >= 0 && s.CompareTo("D") <= 0)
            {
                region = "Africa";
            }
            else if (s.CompareTo("J") >= 0 && s.CompareTo("R") <= 0)
            {
                region = "Asia";
            }
            else if (s.CompareTo("S") >= 0 && s.CompareTo("Z") <= 0)
            {
                region = "Europe";
            }


            return region;
        }

        #endregion

        #region Country

        /// <summary>
        /// Determines the Country of Origin based on a given VIN.
        /// Assumes the vin is valid
        /// </summary>
        /// <param name="vin"></param>
        /// <returns></returns>
        public static string CountryOfOrigin(string vin)
        {
            if (string.IsNullOrEmpty(vin) || vin.Length != _REQUIRED_LENGTH)
            {
                return string.Empty;
            }

            string nvin = vin.ToUpper();
            string country = string.Empty;

            string s = nvin.Substring(0, 1).ToUpper();

            if (s.CompareTo("0") > 0 && s.CompareTo("6") < 0)
            {
                country = GetNorthAmericanCountry(nvin);
            }
            else if (s == "6" || s == "7")
            {
                country = GetOceanicCountry(nvin);
            }
            else if (s == "0" || s == "8" || s == "9")
            {
                country = GetSouthAmericanCountry(nvin);
            }
            else if (s.CompareTo("A") >= 0 && s.CompareTo("D") <= 0)
            {
                country = GetAfricanCountry(nvin);
            }
            else if (s.CompareTo("J") >= 0 && s.CompareTo("R") <= 0)
            {
                country = GetAsianCountry(nvin);
            }
            else if (s.CompareTo("S") >= 0 && s.CompareTo("Z") <= 0)
            {
                country = GetEuropeanCountry(nvin);
            }

            return country;
        }

        private static string GetEuropeanCountry(string vin)
        {
            //SA-SM	United Kingdom
            //SN-ST	Germany
            //SU-SZ	Poland
            //S1-S4	Latvia
            //TA-TH	Switzerland
            //TJ-TP	Czech Republic
            //TR-TV	Hungary
            //TW-T1	Portugal
            //T2-T0	not assigned
            //UA-UG	not assigned
            //UH-UM	Denmark
            //UN-UT	Ireland
            //UU-UZ	Romania
            //U1-U4	not assigned
            //U5-U7	Slovakia
            //U8-U0	not assigned
            //VA-VE	Austria
            //VF-VR	France
            //VS-VW	Spain
            //VX-V2	Yugoslavia
            //V3-V5	Croatia
            //V6-V0	Estonia
            //WA-W0	Germany
            //XA-XE	Bulgaria
            //XF-XK	Greece
            //XL-XR	Netherlands
            //XS-XW	USSR
            //XX-X2	Luxembourg
            //X3-X0	Russia
            //YA-YE	Belgium
            //YF-YK	Finland
            //YL-YR	Malta
            //YS-YW	Sweden
            //YX-Y2	Norway
            //Y3-Y5	Belarus
            //Y6-Y0	Ukraine
            //ZA-ZR	Italy
            //ZS-ZW	not assigned
            //ZX-Z2	Slovenia
            //Z3-Z5	Lithuania
            //Z6-Z0	not assigned
            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "S")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("M") <= 0)
                {
                    country = "United Kingdom";
                }
                else if (s2.CompareTo("N") >= 0 && s2.CompareTo("T") <= 0)
                {
                    country = "Germany";
                }
                else if (s2.CompareTo("U") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "Poland";
                }
                else if (s2.CompareTo("1") >= 0 && s2.CompareTo("4") <= 0)
                {
                    country = "Latvia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "T")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("H") <= 0)
                {
                    country = "Switzerland";
                }
                else if (s2.CompareTo("J") >= 0 && s2.CompareTo("P") <= 0)
                {
                    country = "Czech Republic";
                }
                else if (s2.CompareTo("R") >= 0 && s2.CompareTo("V") <= 0)
                {
                    country = "Hungary";
                }
                else if (s2 == "1" || s2.CompareTo("W") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "Portugal";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "U")
            {
                if (s2.CompareTo("H") >= 0 && s2.CompareTo("M") <= 0)
                {
                    country = "Denmark";
                }
                else if (s2.CompareTo("N") >= 0 && s2.CompareTo("T") <= 0)
                {
                    country = "Ireland";
                }
                else if (s2.CompareTo("U") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "Romania";
                }
                else if (s2.CompareTo("5") >= 0 && s2.CompareTo("7") <= 0)
                {
                    country = "Slovakia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "V")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Austria";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "France";
                }
                else if (s2.CompareTo("S") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "Spain";
                }
                else if (s2 == "X" || s2 == "Y" || s2 == "Z" || s2 == "!" || s2=="2")
                {
                    country = "Yugoslavia";
                }
                else if (s2.CompareTo("3") >= 0 && s2.CompareTo("5") <= 0)
                {
                    country = "Croatia";
                }
                else if (s2 == "0" || s2.CompareTo("6") >= 0 && s2.CompareTo("9") <= 0)
                {
                    country = "Estonia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "W")
            {
                country = "Germany";
            }
            else if (s == "X")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Bulgaria";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Greece";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Netherlands";
                }
                else if (s2.CompareTo("S") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "USSR";
                }
                else if ((s2 == "1" || s2 == "2") || s2.CompareTo("X") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "USSR";
                }
                else if (s2 == "0" || s2.CompareTo("3") >= 0 && s2.CompareTo("9") <= 0)
                {
                    country = "Russia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "Y")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Belgium";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Finland";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Malta";
                }
                else if (s2.CompareTo("S") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "Sweden";
                }
                else if ((s2 == "1" || s2 == "2") || s2.CompareTo("X") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "Sweden";
                }
                else if (s2.CompareTo("3") >= 0 && s2.CompareTo("5") <= 0)
                {
                    country = "Belarus";
                }
                else if (s2 == "0" || s2.CompareTo("6") >= 0 && s2.CompareTo("9") <= 0)
                {
                    country = "Ukraine";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "Z")
            {
                //ZA-ZR	Italy
                //ZS-ZW	not assigned
                //ZX-Z2	Slovenia
                //Z3-Z5	Lithuania
                //Z6-Z0	not assigned
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Italy";
                }
                else if ((s2 == "1" || s2 == "2") || s2.CompareTo("X") >= 0 && s2.CompareTo("Z") <= 0)
                {
                    country = "Slovenia";
                }
                else if (s2.CompareTo("3") >= 0 && s2.CompareTo("5") <= 0)
                {
                    country = "Lithuania";
                }
                else
                {
                    country = string.Empty;
                }
            }

            return country;
        }

        private static string GetAsianCountry(string vin)
        {
            //J Japan
            //KA-KE	Sri Lanka
            //KF-KK	Israel
            //KL-KR	Korea (South)
            //KS-K0	not assigned
            //L China
            //MA-ME	India
            //MF-MK	Indonesia
            //ML-MR	Thailand
            //MS-M0	not assigned
            //NF-NK	Pakistan
            //NL-NR	Turkey
            //NS-N0	not assigned
            //PA-PE	Philippines
            //PF-PK	Singapore
            //PL-PR	Malaysia
            //PS-P0	not assigned
            //RA-RE	United Arab Emirates
            //RF-RK	Taiwan
            //RL-RR	Vietnam
            //RS-R0	not assigned
            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "J")
            {
                country = "Japan";
            }
            else if (s == "L")
            {
                country = "China";
            }
            else if (s == "K")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Sri Lanka";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Israel";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "South Korea";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "M")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "India";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Indonesia";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Thailand";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "N")
            {
                if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Pakistan";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Turkey";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "P")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Philippines";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Singapore";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Malaysia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "R")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "United Arab Emirates";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Taiwan";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Vietnam";
                }
                else
                {
                    country = string.Empty;
                }
            }

            return country;
        }

        private static string GetSouthAmericanCountry(string vin)
        {
            //8A-8E	Argentina
            //8F-8K	Chile
            //8L-8R	Ecuador
            //8S-8W	Peru
            //8X-82	Venezuela
            //83-80	not assigned
            //9A-9E	Brazil
            //9F-9K	Colombia
            //9L-9R	Paraguay
            //9S-9W	Uruguay
            //9X-92	Trinidad & Tobago
            //93–99	Brazil
            //90	not assigned
            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "8")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Argentina";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Chile";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Ecuador";
                }
                else if (s2.CompareTo("S") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "Peru";
                }
                else if (s2 == "X" || s2 == "Y" || s2 == "Z" || s2 == "1" || s2 == "2")
                {
                    country = "Venezuela";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "9")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Brazil";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Columbia";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Paraguay";
                }
                else if (s2.CompareTo("S") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "Uruguay";
                }
                else if (s2 == "X" || s2 == "Y" || s2 == "Z" || s2 == "1" || s2 == "2")
                {
                    country = "Trinidad and Tobago";
                }
                else if (s2.CompareTo("3") >= 0 && s2.CompareTo("9") <= 0)
                {
                    country = "Brazil";
                }
                else
                {
                    country = string.Empty;
                }
            }

            return country;
        }

        private static string GetOceanicCountry(string vin)
        {
            //6A-6W	Australia
            //6X-60	not assigned
            //7A-7E	New Zealand
            //7F-70	not assigned
            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "6")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo( "X") < 0)
                {
                    country = "Australia";
                }
            }
            else if (s == "7")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "New Zealand";
                }
            }

            return country;
        }

        private static string GetNorthAmericanCountry(string vin)
        {
            //1A-10	United States
            //2A-20	Canada
            //3A-3W	Mexico
            //3X-37	Costa Rica
            //38-30	Cayman Islands
            //4A-40	United States
            //5A-50	United States
            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "1" || s == "4" || s == "5")
            {
                country = "United States";
            }
            else if (s == "2")
            {
                country = "Canada";
            }
            else if (s == "3")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("W") <= 0)
                {
                    country = "Mexico";
                }
                else if (s2 == "8" || s2 == "9" || s2 == "0")
                {
                    country = "Cayman Islands";
                }
                else
                {
                    country = "Costa Rica";
                }
            }
            return country;
        }

        private static string GetAfricanCountry(string vin)
        {
            //AA-AH	South Africa
            //AJ-AN	Ivory Coast
            //AP-A0	not assigned
            //BA-BE	Angola
            //BF-BK	Kenya
            //BL-BR	Tanzania
            //BS-B0	not assigned
            //CA-CE	Benin
            //CF-CK	Madagascar
            //CL-CR	Tunisia
            //CS-C0	not assigned
            //DA-DE	Egypt
            //DF-DK	Morocco
            //DL-DR	Zambia
            //DS-D0	not assigned
            //EA-EE	Ethiopia
            //EF-EK	Mozambique
            //EL-E0	not assigned
            //FA-FE	Ghana
            //FF-FK	Nigeria
            //FL-F0	not assigned
            //GA-G0	not assigned
            //HA-H0	not assigned

            string s = vin.Substring(0, 1);
            string s2 = vin.Substring(1, 1);
            string country = string.Empty;

            if (s == "A")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("H") <= 0)
                {
                    country = "South Africa";
                }
                else if (s2.CompareTo("J") >= 0 && s2.CompareTo("N") <= 0)
                {
                    country = "Ivory Coast";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "B")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Angola";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Kenya";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Tanzania";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "C")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Benin";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Madagascar";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Tunisia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "D")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Egypt";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Morocco";
                }
                else if (s2.CompareTo("L") >= 0 && s2.CompareTo("R") <= 0)
                {
                    country = "Zambia";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "E")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Ethiopia";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Mozambique";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else if (s == "F")
            {
                if (s2.CompareTo("A") >= 0 && s2.CompareTo("E") <= 0)
                {
                    country = "Ghana";
                }
                else if (s2.CompareTo("F") >= 0 && s2.CompareTo("K") <= 0)
                {
                    country = "Nigeria";
                }
                else
                {
                    country = string.Empty;
                }
            }
            else
            {
                //GA-G0	not assigned
                //HA-H0	not assigned
                country = string.Empty;
            }

            return country;

        }

        #endregion


        #region Manufacturer

        private static Dictionary<string, string> _manufacturerList;

        /// <summary>
        /// Gets the Manufacturer from the VIN.
        /// Not all Manufacturers are known to this class, but a LOT are.
        /// Assumes the VIN is valid
        /// </summary>
        /// <param name="vin">VIN</param>
        /// <returns>Manufacturers Name</returns>
        public static string Manufacturer(string vin)
        {
            if (string.IsNullOrEmpty(vin) || vin.Length != _REQUIRED_LENGTH)
            {
                return string.Empty;
            }

            if (_manufacturerList == null)
            {
                GenerateManufacturerList();
            }
            
            string manufacturer = string.Empty;
            string s2 = vin.Substring(0, 2);
            string s3 = vin.Substring(0, 3);

            string maniSpecific = ManufacturerDecode.ManufacturerName(vin);

            //Grab Manufacturer Specific before the generic
            if (!string.IsNullOrEmpty(maniSpecific))
            {
                manufacturer = maniSpecific;
            }
            else if (_manufacturerList.ContainsKey(s3)) //Generic (e.g. Mercury)
            {
                manufacturer = _manufacturerList[s3];
            }
            else if (_manufacturerList.ContainsKey(s2)) //Generic Parent (e.g. Ford)
            {
                manufacturer = _manufacturerList[s2];
            }

            return manufacturer.Trim();
        }

        private static void GenerateManufacturerList()
        {
            _manufacturerList = new Dictionary<string, string>();

            _manufacturerList["WMI"] = "Manufacturer";
            _manufacturerList["AFA"] = "Ford South Africa";
            _manufacturerList["AAV"] = "Volkswagen South Africa";
            _manufacturerList["JA3"] = "Mitsubishi";
            _manufacturerList["JA"] = "Isuzu";
            _manufacturerList["JF"] = "Fuji Heavy Industries (Subaru)";
            _manufacturerList["JH"] = "Honda";
            _manufacturerList["JK"] = "Kawasaki (motorcycles)";
            _manufacturerList["JM"] = "Mazda";
            _manufacturerList["JN"] = "Nissan";
            _manufacturerList["JS"] = "Suzuki";
            _manufacturerList["JT"] = "Toyota";
            _manufacturerList["KL"] = "Daewoo General Motors South Korea";
            _manufacturerList["KM8"] = "Hyundai";
            _manufacturerList["KMH"] = "Hyundai";
            _manufacturerList["KNA"] = "Kia";
            _manufacturerList["KNB"] = "Kia";
            _manufacturerList["KNC"] = "Kia";
            _manufacturerList["KNM"] = "Renault Samsung";
            _manufacturerList["L56"] = "Renault Samsung";
            _manufacturerList["L5Y"] = "Merato Motorcycle Taizhou Zhongneng";
            _manufacturerList["LDY"] = "Zhongtong Coach, China";
            _manufacturerList["LKL"] = "Suzhou King Long, China";
            _manufacturerList["LSY"] = "Brilliance Zhonghua";
            _manufacturerList["LTV"] = "Toyota Tian Jin";
            _manufacturerList["LVS"] = "Ford Chang An";
            _manufacturerList["LVV"] = "Chery, China";
            _manufacturerList["LZM"] = "MAN China";
            _manufacturerList["LZE"] = "Isuzu Guangzhou, China";
            _manufacturerList["LZG"] = "Shaanxi Automobile Group, China";
            _manufacturerList["LZY"] = "Yutong Zhengzhou, China";
            _manufacturerList["MA3"] = "Suzuki India";
            _manufacturerList["MNB"] = "Ford Thailand";
            _manufacturerList["MNT"] = "Nissan Thailand";
            _manufacturerList["MMT"] = "Mitsubishi Thailand";
            _manufacturerList["MM8"] = "Mazda Thailand";
            _manufacturerList["MPA"] = "Isuzu Thailand";
            _manufacturerList["MP1"] = "Isuzu Thailand";
            _manufacturerList["MRH"] = "Honda Thailand";
            _manufacturerList["MR0"] = "Toyota Thailand";
            _manufacturerList["NLE"] = "Mercedes-Benz Turk Truck";
            _manufacturerList["NM0"] = "Ford Turkey";
            _manufacturerList["NM4"] = "Tofas Turk";
            _manufacturerList["NMT"] = "Toyota Turkiye";
            _manufacturerList["PE3"] = "Mazda Phillipines";
            _manufacturerList["SAL"] = "Land Rover";
            _manufacturerList["SAJ"] = "Jaguar";
            _manufacturerList["SCC"] = "Lotus Cars";
            _manufacturerList["SCE"] = "DeLorean Motor Cars N. Ireland (UK)";
            _manufacturerList["SDB"] = "Peugeot UK";
            _manufacturerList["SFD"] = "Alexander Dennis UK";
            _manufacturerList["SHS"] = "Honda UK";
            _manufacturerList["SJN"] = "Nissan UK";
            _manufacturerList["TMB"] = "Škoda";
            _manufacturerList["TMT"] = "Tatra";
            _manufacturerList["TRA"] = "Ikarus Bus";
            _manufacturerList["TRU"] = "Audi Hungary";
            _manufacturerList["TSM"] = "Suzuki, (Hungary)";
            _manufacturerList["UU1"] = "Renault Dacia, (Romania)";
            _manufacturerList["VF1"] = "Renault";
            _manufacturerList["VF3"] = "Peugeot";
            _manufacturerList["VF6"] = "Renault (Trucks)";
            _manufacturerList["VF7"] = "Citroën";
            _manufacturerList["VF8"] = "Matra";
            _manufacturerList["VSS"] = "SEAT";
            _manufacturerList["VSX"] = "Opel Spain";
            _manufacturerList["VS6"] = "Ford Spain";
            _manufacturerList["VSK"] = "Nissan Spain";
            _manufacturerList["VSE"] = "Suzuki Spain (Santana Motors)";
            _manufacturerList["VWV"] = "Volkswagen Spain";
            _manufacturerList["VX1"] = "Zastava / Yugo Serbia";
            _manufacturerList["WAG"] = "Neoplan";
            _manufacturerList["WAU"] = "Audi";
            _manufacturerList["WBA"] = "BMW";
            _manufacturerList["WBS"] = "BMW M";
            _manufacturerList["WDB"] = "Mercedes-Benz";
            _manufacturerList["WDC"] = "DaimlerChrysler";
            _manufacturerList["WDD"] = "McLaren";
            _manufacturerList["WF0"] = "Ford Germany";
            _manufacturerList["WMA"] = "MAN Germany";
            _manufacturerList["WMW"] = "MINI";
            _manufacturerList["WP0"] = "Porsche";
            _manufacturerList["W0L"] = "Opel";
            _manufacturerList["WVW"] = "Volkswagen";
            _manufacturerList["WV1"] = "Volkswagen Commercial Vehicles";
            _manufacturerList["WV2"] = "Volkswagen Bus/Van";
            _manufacturerList["XL9"] = "Spyker";
            _manufacturerList["XTA"] = "Lada/AutoVaz (Russia)";
            _manufacturerList["YK1"] = "Saab";
            _manufacturerList["YS2"] = "Scania AB";
            _manufacturerList["YS3"] = "Saab";
            _manufacturerList["YS4"] = "Scania Bus";
            _manufacturerList["YV1"] = "Volvo Cars";
            _manufacturerList["YV4"] = "Volvo Cars";
            _manufacturerList["YV2"] = "Volvo Trucks";
            _manufacturerList["YV3"] = "Volvo Buses";
            _manufacturerList["ZAM"] = "Maserati Biturbo";
            _manufacturerList["ZAP"] = "Piaggio/Vespa/Gilera";
            _manufacturerList["ZAR"] = "Alfa Romeo";
            _manufacturerList["ZCG"] = "Cagiva SpA";
            _manufacturerList["ZDM"] = "Ducati Motor Holdings SpA";
            _manufacturerList["ZDF"] = "Ferrari Dino";
            _manufacturerList["ZD4"] = "Aprilia";
            _manufacturerList["ZFA"] = "Fiat";
            _manufacturerList["ZFC"] = "Fiat V.I.";
            _manufacturerList["ZFF"] = "Ferrari";
            _manufacturerList["ZHW"] = "Lamborghini";
            _manufacturerList["ZLA"] = "Lancia";
            _manufacturerList["ZOM"] = "OM";
            _manufacturerList["1C3"] = "Chrysler";
            _manufacturerList["1D3"] = "Dodge";
            _manufacturerList["1FA"] = "Ford Motor Company";
            _manufacturerList["1FB"] = "Ford Motor Company";
            _manufacturerList["1FC"] = "Ford Motor Company";
            _manufacturerList["1FD"] = "Ford Motor Company";
            _manufacturerList["1FM"] = "Ford Motor Company";
            _manufacturerList["1FT"] = "Ford Motor Company";
            _manufacturerList["1FU"] = "Freightliner";
            _manufacturerList["1FV"] = "Freightliner";
            _manufacturerList["1F9"] = "FWD Corp.";
            _manufacturerList["1G"] = "General Motors USA";
            _manufacturerList["1GC"] = "Chevrolet Truck USA";
            _manufacturerList["1GT"] = "GMC Truck USA";
            _manufacturerList["1G1"] = "Chevrolet USA";
            _manufacturerList["1G2"] = "Pontiac USA";
            _manufacturerList["1G3"] = "Oldsmobile USA";
            _manufacturerList["1G4"] = "Buick USA";
            _manufacturerList["1G6"] = "Cadillac USA";
            _manufacturerList["1GM"] = "Pontiac USA";
            _manufacturerList["1G8"] = "Saturn USA";
            _manufacturerList["1H"] = "Honda USA";
            _manufacturerList["1HD"] = "Harley-Davidson";
            _manufacturerList["1J4"] = "Jeep";
            _manufacturerList["1L"] = "Lincoln USA";
            _manufacturerList["1ME"] = "Mercury USA";
            _manufacturerList["1M1"] = "Mack Truck USA";
            _manufacturerList["1M2"] = "Mack Truck USA";
            _manufacturerList["1M3"] = "Mack Truck USA";
            _manufacturerList["1M4"] = "Mack Truck USA";
            _manufacturerList["1N"] = "Nissan USA";
            _manufacturerList["1NX"] = "NUMMI USA";
            _manufacturerList["1P3"] = "Plymouth USA";
            _manufacturerList["1R9"] = "Roadrunner Hay Squeeze USA";
            _manufacturerList["1VW"] = "Volkswagen USA";
            _manufacturerList["1XK"] = "Kenworth USA";
            _manufacturerList["1XP"] = "Peterbilt USA";
            _manufacturerList["1YV"] = "Mazda USA (AutoAlliance International)";
            _manufacturerList["2C3"] = "Chrysler Canada";
            _manufacturerList["2CN"] = "CAMI";
            _manufacturerList["2D3"] = "Dodge Canada";
            _manufacturerList["2FA"] = "Ford Motor Company Canada";
            _manufacturerList["2FB"] = "Ford Motor Company Canada";
            _manufacturerList["2FC"] = "Ford Motor Company Canada";
            _manufacturerList["2FM"] = "Ford Motor Company Canada";
            _manufacturerList["2FT"] = "Ford Motor Company Canada";
            _manufacturerList["2FU"] = "Freightliner";
            _manufacturerList["2FV"] = "Freightliner";
            _manufacturerList["2FZ"] = "Sterling";
            _manufacturerList["2G"] = "General Motors Canada";
            _manufacturerList["2G1"] = "Chevrolet Canada";
            _manufacturerList["2G2"] = "Pontiac Canada";
            _manufacturerList["2G3"] = "Oldsmobile Canada";
            _manufacturerList["2G4"] = "Buick Canada";
            _manufacturerList["2HG"] = "Honda Canada";
            _manufacturerList["2HK"] = "Honda Canada";
            _manufacturerList["2HM"] = "Hyundai Canada";
            _manufacturerList["2M"] = "Mercury";
            _manufacturerList["2P3"] = "Plymouth Canada";
            _manufacturerList["2T"] = "Toyota Canada";
            _manufacturerList["2WK"] = "Western Star";
            _manufacturerList["2WL"] = "Western Star";
            _manufacturerList["2WM"] = "Western Star";
            _manufacturerList["3D3"] = "Dodge Mexico";
            _manufacturerList["3FE"] = "Ford Motor Company Mexico";
            _manufacturerList["3G"] = "General Motors Mexico";
            _manufacturerList["3H"] = "Honda Mexico";
            _manufacturerList["3N"] = "Nissan Mexico";
            _manufacturerList["3P3"] = "Plymouth Mexico";
            _manufacturerList["3VW"] = "Volkswagen Mexico";
            _manufacturerList["4F"] = "Mazda USA";
            _manufacturerList["4M"] = "Mercury";
            _manufacturerList["4S"] = "Subaru-Isuzu Automotive";
            _manufacturerList["4T"] = "Toyota";
            _manufacturerList["4US"] = "BMW USA";
            _manufacturerList["4UZ"] = "Frt-Thomas Bus";
            _manufacturerList["4V1"] = "Volvo";
            _manufacturerList["4V2"] = "Volvo";
            _manufacturerList["4V3"] = "Volvo";
            _manufacturerList["4V4"] = "Volvo";
            _manufacturerList["4V5"] = "Volvo";
            _manufacturerList["4V6"] = "Volvo";
            _manufacturerList["4VL"] = "Volvo";
            _manufacturerList["4VM"] = "Volvo";
            _manufacturerList["4VZ"] = "Volvo";
            _manufacturerList["5F"] = "Honda USA-Alabama";
            _manufacturerList["5L"] = "Lincoln";
            _manufacturerList["5N1"] = "Nissan USA";
            _manufacturerList["5NP"] = "Hyundai USA";
            _manufacturerList["5T"] = "Toyota USA - trucks";
            _manufacturerList["6AB"] = "MAN Australia";
            _manufacturerList["6F"] = "Ford Motor Company Australia";
            _manufacturerList["6G2"] = "Pontiac Australia (GTO & G8)";
            _manufacturerList["6H"] = "General Motors-Holden";
            _manufacturerList["6MM"] = "Mitsubishi Motors Australia";
            _manufacturerList["6T1"] = "Toyota Motor Corporation Australia";
            _manufacturerList["8AG"] = "Chevrolet Argentina";
            _manufacturerList["8GG"] = "Chevrolet Chile";
            _manufacturerList["8AP"] = "Fiat Argentina";
            _manufacturerList["8AF"] = "Ford Motor Company Argentina";
            _manufacturerList["8AD"] = "Peugeot Argentina";
            _manufacturerList["8GD"] = "Peugeot Chile";
            _manufacturerList["8A1"] = "Renault Argentina";
            _manufacturerList["8AK"] = "Suzuki Argentina";
            _manufacturerList["8AJ"] = "Toyota Argentina";
            _manufacturerList["8AW"] = "Volkswagen Argentina";
            _manufacturerList["93U"] = "Audi Brazil";
            _manufacturerList["9BG"] = "Chevrolet Brazil";
            _manufacturerList["935"] = "Citroën Brazil";
            _manufacturerList["9BD"] = "Fiat Brazil";
            _manufacturerList["9BF"] = "Ford Motor Company Brazil";
            _manufacturerList["93H"] = "Honda Brazil";
            _manufacturerList["9BM"] = "Mercedes-Benz Brazil";
            _manufacturerList["936"] = "Peugeot Brazil";
            _manufacturerList["93Y"] = "Renault Brazil";
            _manufacturerList["9BS"] = "Scania Brazil";
            _manufacturerList["93R"] = "Toyota Brazil";
            _manufacturerList["9BW"] = "Volkswagen Brazil";
            _manufacturerList["9FB"] = "Renault Colombia";

            _manufacturerList["5YJ"] = "Tesla Motors";
            _manufacturerList["SFZ"] = "Tesla Motors";
            _manufacturerList["5J1"] = "Big Dog Motorcycles";
            _manufacturerList["JNK"] = "Infininti";
            _manufacturerList["19U"] = "Honda of America (Acura)";
            _manufacturerList["JH4"] = "Honda Motor Co. Passenger Vehicle";
            _manufacturerList["2HN"] = "Honda of Canada (Acura)";
            _manufacturerList["SCF"] = "Aston Martin";

        }

        #endregion


        #region Year

        public static int Year1(string vin)
        {
            int i = 0;
            if (!string.IsNullOrEmpty(vin) && vin.Length == _REQUIRED_LENGTH)
            {
                i = GetYear(vin, false);
            }
            return i;
        }

        public static int Year2(string vin)
        {
            int i = 0;
            if (!string.IsNullOrEmpty(vin) && vin.Length == _REQUIRED_LENGTH)
            {
                i = GetYear(vin, true);
            }
            return i;
        }

        private static int GetYear(string vin, bool secondYear)
        {
            int i = 0;
            string y = vin.Substring(9, 1); //10th digit = the year
            int latestYear = DateTime.Today.Year + 1;
            latestYear = latestYear > 2010 ? latestYear : 2011; //the last year valid when this was written

            int fYear = 0;
            int sYear = 0;

            switch (y)
            {
                case "0": //0 is technically invalid. But some manufacturers used it for 1980 instead of A
                    fYear = 1980;
                    break;
                case "A":
                    fYear = 1980;
                    sYear = 2010;
                    break;
                case "B":
                    fYear = 1981;
                    sYear = 2011;
                    break;
                case "C":
                    fYear = 1982;
                    sYear = 2012;
                    break;
                case "D":
                    fYear = 1983;
                    sYear = 2013;
                    break;
                case "E":
                    fYear = 1984;
                    sYear = 2014;
                    break;
                case "F":
                    fYear = 1985;
                    sYear = 2015;
                    break;
                case "G":
                    fYear = 1986;
                    sYear = 2016;
                    break;
                case "H":
                    fYear = 1987;
                    sYear = 2017;
                    break;
                case "J":
                    fYear = 1988;
                    sYear = 2018;
                    break;
                case "K":
                    fYear = 1989;
                    sYear = 2019;
                    break;
                case "L":
                    fYear = 1990;
                    sYear = 2020;
                    break;
                case "M":
                    fYear = 1991;
                    sYear = 2021;
                    break;
                case "N":
                    fYear = 1992;
                    sYear = 2022;
                    break;
                case "P":
                    fYear = 1993;
                    sYear = 2023;
                    break;
                case "R":
                    fYear = 1994;
                    sYear = 2024;
                    break;
                case "S":
                    fYear = 1995;
                    sYear = 2025;
                    break;
                case "T":
                    fYear = 1996;
                    sYear = 2026;
                    break;
                case "V":
                    fYear = 1997;
                    sYear = 2027;
                    break;
                case "W":
                    fYear = 1998;
                    sYear = 2028;
                    break;
                case "X":
                    fYear = 1999;
                    sYear = 2029;
                    break;
                case "Y":
                    fYear = 2000;
                    sYear = 2030;
                    break;
                case "1":
                    fYear = 2001;
                    sYear = 2031;
                    break;
                case "2":
                    fYear = 2002;
                    sYear = 2032;
                    break;
                case "3":
                    fYear = 2003;
                    sYear = 2033;
                    break;
                case "4":
                    fYear = 2004;
                    sYear = 2034;
                    break;
                case "5":
                    fYear = 2005;
                    sYear = 2035;
                    break;
                case "6":
                    fYear = 2006;
                    sYear = 2036;
                    break;
                case "7":
                    fYear = 2007;
                    sYear = 2037;
                    break;
                case "8":
                    fYear = 2008;
                    sYear = 2038;
                    break;
                case "9":
                    fYear = 2009;
                    sYear = 2039;
                    break;
            }

            if (secondYear)
            {
                if (sYear <= latestYear)
                {
                    i = sYear;
                }
            }
            else
            {
                i = fYear;
            }

            return i;
        }

        #endregion


        #endregion
    }
}
